?? style-guide.txt
字號:
ret = my_func(bar, baz); if (!ret) return -1; #ifdef BB_FEATURE_FUNKY maybe_do_funky_stuff(bar, baz); #endif Do this instead: (in .h header file) #ifdef BB_FEATURE_FUNKY static inline void maybe_do_funky_stuff (int bar, int baz) { /* lotsa code in here */ } #else static inline void maybe_do_funky_stuff (int bar, int baz) {} #endif (in the .c source file) ret = my_func(bar, baz); if (!ret) return -1; maybe_do_funky_stuff(bar, baz);The great thing about this approach is that the compiler will optimize awaythe "no-op" case (the empty function) when the feature is turned off.Note also the use of the word 'maybe' in the function name to indicateconditional execution.Notes on Strings----------------Strings in C can get a little thorny. Here's some guidelines for dealing withstrings in Busybox. (There is surely more that could be added to thissection.)String Files~~~~~~~~~~~~Put all help/usage messages in usage.c. Put other strings in messages.c.Putting these strings into their own file is a calculated decision designed toconfine spelling errors to a single place and aid internationalizationefforts, if needed. (Side Note: we might want to use a single file - maybecalled 'strings.c' - instead of two, food for thought).Testing String Equivalence~~~~~~~~~~~~~~~~~~~~~~~~~~There's a right way and a wrong way to test for sting equivalence withstrcmp(): The wrong way: if (!strcmp(string, "foo")) { ... The right way: if (strcmp(string, "foo") == 0){ ...The use of the "equals" (==) operator in the latter example makes it much moreobvious that you are testing for equivalence. The former example with the"not" (!) operator makes it look like you are testing for an error. In a moreperfect world, we would have a streq() function in the string library, butthat ain't the world we're living in.Avoid Dangerous String Functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Unfortunately, the way C handles strings makes them prone to overruns whencertain library functions are (mis)used. The following table offers a summaryof some of the more notorious troublemakers:function overflows preferred----------------------------------------strcpy dest string strncpystrcat dest string strncatgets string it gets fgetsgetwd buf string getcwd[v]sprintf str buffer [v]snprintfrealpath path buffer use with pathconf[vf]scanf its arguments just avoid itThe above is by no means a complete list. Be careful out there.Avoid Big Static Buffers------------------------First, some background to put this discussion in context: Static buffers looklike this in code: /* in a .c file outside any functions */ static char *buffer[BUFSIZ]; /* happily used by any function in this file, but ick! big! */The problem with these is that any time any busybox app is run, you pay amemory penalty for this buffer, even if the applet that uses said buffer isnot run. This can be fixed, thusly: static char *buffer; ... other_func() { strcpy(buffer, lotsa_chars); /* happily uses global *buffer */ ... foo_main() { buffer = xmalloc(sizeof(char)*BUFSIZ); ...However, this approach trades bss segment for text segment. Rather thanmallocing the buffers (and thus growing the text size), buffers can bedeclared on the stack in the *_main() function and made available globally byassigning them to a global pointer thusly: static char *pbuffer; ... other_func() { strcpy(pbuffer, lotsa_chars); /* happily uses global *pbuffer */ ... foo_main() { char *buffer[BUFSIZ]; /* declared locally, on stack */ pbuffer = buffer; /* but available globally */ ...This last approach has some advantages (low code size, space not used untilit's needed), but can be a problem in some low resource machines that havevery limited stack space (e.g., uCLinux).A macro is declared in busybox.h that implements compile-time selectionbetween xmalloc() and stack creation, so you can code the line in question as RESERVE_BB_BUFFER(buffer, BUFSIZ);and the right thing will happen, based on your configuration.Miscellaneous Coding Guidelines-------------------------------The following are important items that don't fit into any of the abovesections.Model Busybox Applets After GNU Counterparts~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~When in doubt about the proper behavior of a Busybox program (output,formatting, options, etc.), model it after the equivalent GNU program.Doesn't matter how that program behaves on some other flavor of *NIX; doesn'tmatter what the POSIX standard says or doesn't say, just model Busyboxprograms after their GNU counterparts and it will make life easier on (nearly)everyone.The only time we deviate from emulating the GNU behavior is when: - We are deliberately not supporting a feature (such as a command line switch) - Emulating the GNU behavior is prohibitively expensive (lots more code would be required, lots more memory would be used, etc.) - The difference is minor or cosmeticA note on the 'cosmetic' case: Output differences might be consideredcosmetic, but if the output is significant enough to break other scripts thatuse the output, it should really be fixed.Scope~~~~~If a const variable is used only in a single source file, put it in the sourcefile and not in a header file. Likewise, if a const variable is used in onlyone function, do not make it global to the file. Instead, declare it insidethe function body. Bottom line: Make a conscious effort to limit declarationsto the smallest scope possible.Inside applet files, all functions should be declared static so as to keep theglobal name space clean. The only exception to this rule is the "applet_main"function which must be declared extern.If you write a function that performs a task that could be useful outside theimmediate file, turn it into a general-purpose function with no ties to anyapplet and put it in the utility.c file instead.Brackets Are Your Friends~~~~~~~~~~~~~~~~~~~~~~~~~Please use brackets on all if and else statements, even if it is only oneline. Example: Don't do this: if (foo) stmt1; stmt2 stmt3; Do this instead: if (foo) { stmt1; } stmt2 stmt3;The "bracketless" approach is error prone because someday you might add a linelike this: if (foo) stmt1; new_line(); stmt2 stmt3;And the resulting behavior of your program would totally bewilder you. (Don'tlaugh, it happens to us all.) Remember folks, this is C, not Python.Function Declarations~~~~~~~~~~~~~~~~~~~~~Do not use old-style function declarations that declare variable types betweenthe parameter list and opening bracket. Example: Don't do this: int foo(parm1, parm2) char parm1; float parm2; { .... Do this instead: int foo(char parm1, float parm2) { ....The only time you would ever need to use the old declaration syntax is tosupport ancient, antediluvian compilers. To our good fortune, we have accessto more modern compilers and the old declaration syntax is neither necessarynor desired.Emphasizing Logical Blocks~~~~~~~~~~~~~~~~~~~~~~~~~~Organization and readability are improved by putting extra newlines aroundblocks of code that perform a single task. These are typically blocks thatbegin with a C keyword, but not always.Furthermore, you should put a single comment (not necessarily one line, justone comment) before the block, rather than commenting each and every line.There is an optimal ammount of commenting that a program can have; you cancomment too much as well as too little.A picture is really worth a thousand words here, the following exampleillustrates how to emphasize logical blocks: while (line = get_line_from_file(fp)) { /* eat the newline, if any */ chomp(line); /* ignore blank lines */ if (strlen(file_to_act_on) == 0) { continue; } /* if the search string is in this line, print it, * unless we were told to be quiet */ if (strstr(line, search) && !be_quiet) { puts(line); } /* clean up */ free(line); }Processing Options with getopt~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~If your applet needs to process command-line switches, please use getopt() todo so. Numerous examples can be seen in many of the existing applets, butbasically it boils down to two things: at the top of the .c file, have thisline in the midst of your #includes: #include <getopt.h>And a code block similar to the following near the top of your applet_main()routine: while ((opt = getopt(argc, argv, "abc")) > 0) { switch (opt) { case 'a': do_a_opt = 1; break; case 'b': do_b_opt = 1; break; case 'c': do_c_opt = 1; break; default: show_usage(); /* in utility.c */ } }If your applet takes no options (such as 'init'), there should be a linesomewhere in the file reads: /* no options, no getopt */That way, when people go grepping to see which applets need to be converted touse getopt, they won't get false positives.Additional Note: Do not use the getopt_long library function and do not try tohand-roll your own long option parsing. Busybox applets should only supportshort options. Explanations and examples of the short options should bedocumented in usage.h.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -