Viewing file:      ugrep.cpp (14.44 KB)      -rw-r--r-- Select action/file-type:    (+) |   (+) |   (+) | Code (+) | Session (+) |   (+) | SDB (+) |   (+) |   (+) |   (+) |   (+) |   (+) |
 
/************************************************************************* * *   © 2016 and later: Unicode, Inc. and others. *   License & terms of use: http://www.unicode.org/copyright.html * ************************************************************************** ************************************************************************** * *   Copyright (C) 2002-2010, International Business Machines *   Corporation and others.  All Rights Reserved. * *************************************************************************** */
  // //   ugrep  - an ICU sample program illustrating the use of ICU Regular Expressions. // //            The use of the ICU Regex API all occurs within the main() //            function.  The rest of the code deals with opening files, //            encoding conversions, printing results, etc. // //            This is not a full-featured grep program.  The command line options //            have been kept to a minimum to avoid complicating the sample code. //
 
 
  #include <stdio.h> #include <stdlib.h> #include <string.h>
  #include "unicode/utypes.h" #include "unicode/ustring.h" #include "unicode/regex.h" #include "unicode/ucnv.h" #include "unicode/uclean.h"
  using namespace icu;
  // //  The following variables contain parameters that may be set from the command line. // const char *pattern = nullptr;     // The regular expression int        firstFileNum;        //  argv index of the first file name UBool      displayFileName = false; UBool      displayLineNum  = false;
 
  // //  Info regarding the file currently being processed // const char *fileName;       int         fileLen;              // Length, in UTF-16 Code Units.  
  char16_t *ucharBuf = nullptr; // Buffer, holds converted file.  (Simple minded program, always reads                               //   the whole file at once.
  char *charBuf = nullptr; // Buffer, for original, unconverted file data.
  // //  Info regarding the line currently being processed // int      lineStart;     // Index of first char of the current line in the file buffer int      lineEnd;       // Index of char following the new line sequence for the current line int      lineNum;
  // //  Converter, used on output to convert Unicode data back to char * //             so that it will display in non-Unicode terminal windows. // UConverter *outConverter = nullptr;
  // //  Function forward declarations // void processOptions(int argc, const char **argv); void nextLine(int start); void printMatch(); void printUsage(); void readFile(const char *name);
 
 
  //------------------------------------------------------------------------------------------ // //   main          for ugrep // //           Structurally, all use of the ICU Regular Expression API is in main(), //           and all of the supporting stuff necessary to make a running program, but //           not directly related to regular expressions, is factored out into these other //           functions. // //------------------------------------------------------------------------------------------ int main(int argc, const char** argv) {     UBool     matchFound = false;
      //     //  Process the command line options.     //     processOptions(argc, argv);
      //     // Create a RegexPattern object from the user supplied pattern string.     //     UErrorCode status = U_ZERO_ERROR;   // All ICU operations report success or failure                                         //   in a status variable.
      UParseError    parseErr;            // In the event of a syntax error in the regex pattern,                                         //   this struct will contain the position of the                                         //   error.
      RegexPattern  *rePat = RegexPattern::compile(pattern, parseErr, status);                                         // Note that C++ is doing an automatic conversion                                         //  of the (char *) pattern to a temporary                                         //  UnicodeString object.     if (U_FAILURE(status)) {         fprintf(stderr, "ugrep:  error in pattern: \"%s\" at position %d\n",             u_errorName(status), parseErr.offset);         exit(-1);     }
      //     // Create a RegexMatcher from the newly created pattern.     //     UnicodeString empty;     RegexMatcher *matcher = rePat->matcher(empty, status);     if (U_FAILURE(status)) {         fprintf(stderr, "ugrep:  error in creating RegexMatcher: \"%s\"\n",             u_errorName(status));         exit(-1);     }
      //     // Loop, processing each of the input files.     //     for (int fileNum=firstFileNum; fileNum < argc; fileNum++) {         readFile(argv[fileNum]);
          //         //  Loop through the lines of a file, trying to match the regex pattern on each.         //         for (nextLine(0); lineStart<fileLen; nextLine(lineEnd)) {             UnicodeString s(false, ucharBuf+lineStart, lineEnd-lineStart);             matcher->reset(s);             if (matcher->find()) {                 matchFound = true;                 printMatch();             }         }     }
      //     //  Clean up     //     delete matcher;     delete rePat;     free(ucharBuf);     free(charBuf);     ucnv_close(outConverter);          u_cleanup();       // shut down ICU, release any cached data it owns.
      return matchFound? 0: 1; }
 
 
  //------------------------------------------------------------------------------------------ // //   doOptions          Run through the command line options, and set //                      the global variables accordingly. // //                      exit without returning if an error occurred and //                      ugrep should not proceed further. // //------------------------------------------------------------------------------------------ void processOptions(int argc, const char **argv) {     int            optInd;     UBool          doUsage   = false;     UBool          doVersion = false;     const char    *arg;
 
      for(optInd = 1; optInd < argc; ++optInd) {         arg = argv[optInd];                  /* version info */         if(strcmp(arg, "-V") == 0 || strcmp(arg, "--version") == 0) {             doVersion = true;         }         /* usage info */         else if(strcmp(arg, "--help") == 0) {             doUsage = true;         }         else if(strcmp(arg, "-n") == 0 || strcmp(arg, "--line-number") == 0) {             displayLineNum = true;         }         /* POSIX.1 says all arguments after -- are not options */         else if(strcmp(arg, "--") == 0) {             /* skip the -- */             ++optInd;             break;         }         /* unrecognized option */         else if(strncmp(arg, "-", strlen("-")) == 0) {             printf("ugrep: invalid option -- %s\n", arg+1);             doUsage = true;         }         /* done with options */         else {             break;         }     }
      if (doUsage) {         printUsage();         exit(0);     }
      if (doVersion) {         printf("ugrep version 0.01\n");         if (optInd == argc) {             exit(0);         }     }
      int  remainingArgs = argc-optInd;     // pattern file ...     if (remainingArgs < 2) {         fprintf(stderr, "ugrep:  files or pattern are missing.\n");         printUsage();         exit(1);     }
      if (remainingArgs > 2) {         // More than one file to be processed.   Display file names with match output.         displayFileName = true;     }
      pattern      = argv[optInd];     firstFileNum = optInd+1; }
  //------------------------------------------------------------------------------------------ // //   printUsage // //------------------------------------------------------------------------------------------ void printUsage() {     printf("ugrep [options] pattern file...\n"         "     -V or --version     display version information\n"         "     --help              display this help and exit\n"         "     --                  stop further option processing\n"         "-n,  --line-number       Prefix each line of output with the line number within its input file.\n"         );     exit(0); }
  //------------------------------------------------------------------------------------------ // //    readFile          Read a file into memory, and convert it to Unicode. // //                      Since this is just a demo program, take the simple minded approach //                      of always reading the whole file at once.  No intelligent buffering //                      is done. // //------------------------------------------------------------------------------------------ void readFile(const char *name) {
      //     //  Initialize global file variables     //     fileName = name;     fileLen  = 0;      // zero length prevents processing in case of errors.
 
      //     //  Open the file and determine its size.     //     FILE *file = fopen(name, "rb");     if (file == nullptr) {         fprintf(stderr, "ugrep: Could not open file \"%s\"\n", fileName);         return;     }     fseek(file, 0, SEEK_END);     int rawFileLen = ftell(file);     fseek(file, 0, SEEK_SET);     
      //     //   Read in the file     //     charBuf = static_cast<char*>(realloc(charBuf, rawFileLen + 1)); // Need error checking...     int t = static_cast<int>(fread(charBuf, 1, rawFileLen, file));     if (t != rawFileLen)  {         fprintf(stderr, "Error reading file \"%s\"\n", fileName);         fclose(file);         return;     }     charBuf[rawFileLen]=0;     fclose(file);
      //     // Look for a Unicode Signature (BOM) in the data     //     int32_t        signatureLength;     const char *   charDataStart = charBuf;     UErrorCode     status        = U_ZERO_ERROR;     const char*    encoding      = ucnv_detectUnicodeSignature(                            charDataStart, rawFileLen, &signatureLength, &status);     if (U_FAILURE(status)) {         fprintf(stderr, "ugrep: ICU Error \"%s\" from ucnv_detectUnicodeSignature()\n",             u_errorName(status));         return;     }     if(encoding!=nullptr ){         charDataStart  += signatureLength;         rawFileLen     -= signatureLength;     }
      //     // Open a converter to take the file to UTF-16     //     UConverter* conv;     conv = ucnv_open(encoding, &status);     if (U_FAILURE(status)) {         fprintf(stderr, "ugrep: ICU Error \"%s\" from ucnv_open()\n", u_errorName(status));         return;     }
      //     // Convert the file data to char16_t.     //  Preflight first to determine required buffer size.     //     uint32_t destCap = ucnv_toUChars(conv,                        nullptr,           //  dest,                        0,              //  destCapacity,                        charDataStart,                        rawFileLen,                        &status);     if (status != U_BUFFER_OVERFLOW_ERROR) {         fprintf(stderr, "ugrep: ucnv_toUChars: ICU Error \"%s\"\n", u_errorName(status));         return;     };          status = U_ZERO_ERROR;     ucharBuf = static_cast<char16_t*>(realloc(ucharBuf, (destCap + 1) * sizeof(char16_t)));     ucnv_toUChars(conv,         ucharBuf,           //  dest,         destCap+1,         charDataStart,         rawFileLen,         &status);     if (U_FAILURE(status)) {         fprintf(stderr, "ugrep: ucnv_toUChars: ICU Error \"%s\"\n", u_errorName(status));         return;     };     ucnv_close(conv);          //     //  Successful conversion.  Set the global size variables so that     //     the rest of the processing will proceed for this file.     //     fileLen = destCap; }               
 
  //------------------------------------------------------------------------------------------ // //   nextLine           Advance the line index variables, starting at the //                      specified position in the input file buffer, by //                      scanning forward until the next end-of-line. // //                      Need to take into account all of the possible Unicode //                      line ending sequences. // //------------------------------------------------------------------------------------------ void nextLine(int  startPos) {     if (startPos == 0) {         lineNum = 0;     } else {         lineNum++;     }     lineStart = lineEnd = startPos;
      for (;;) {         if (lineEnd >= fileLen) {             return;         }         char16_t c = ucharBuf[lineEnd];         lineEnd++;         if (c == 0x0a   ||       // Line Feed             c == 0x0c   ||       // Form Feed             c == 0x0d   ||       // Carriage Return             c == 0x85   ||       // Next Line             c == 0x2028 ||       // Line Separator             c == 0x2029)         // Paragraph separator         {              break;         }     }
      // Check for CR/LF sequence, and advance over the LF if we're in the middle of one.     if (lineEnd < fileLen           &&         ucharBuf[lineEnd-1] == 0x0d &&         ucharBuf[lineEnd]   == 0x0a)      {         lineEnd++;     } }
 
  //------------------------------------------------------------------------------------------ // //   printMatch         Called when a matching line has been located. //                      Print out the line from the file with the match, after //                         converting it back to the default code page. // //------------------------------------------------------------------------------------------ void printMatch() {     char                buf[2000];     UErrorCode         status       = U_ZERO_ERROR;
      // If we haven't already created a converter for output, do it now.     if (outConverter == nullptr) {         outConverter = ucnv_open(nullptr, &status);         if (U_FAILURE(status)) {             fprintf(stderr, "ugrep:  Error opening default converter: \"%s\"\n",                 u_errorName(status));             exit(-1);         }     };
      // Convert the line to be printed back to the default 8 bit code page.     //   If the line is too long for our buffer, just truncate it.     ucnv_fromUChars(outConverter,                     buf,                   // destination buffer for conversion                     sizeof(buf),           // capacity of destination buffer                     &ucharBuf[lineStart],   // Input to conversion                     lineEnd-lineStart,     // number of UChars to convert                     &status);     buf[sizeof(buf)-1] = 0;                // Add null for use in case of too long lines.                                            // The converter null-terminates its output unless                                            //   the buffer completely fills.         if (displayFileName) {         printf("%s:", fileName);     }     if (displayLineNum) {         printf("%d:", lineNum);     }     printf("%s", buf); }      
  |